package com.accedo.achievements.services.ajax.impl;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.annotation.Resource;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.accedo.achievements.dataaccess.dao.impl.AchievementDaoImpl;
import com.accedo.achievements.dataaccess.dao.impl.AppDaoImpl;
import com.accedo.achievements.dataaccess.dao.impl.UserDaoImpl;
import com.accedo.achievements.dataaccess.model.App;
import com.accedo.achievements.dataaccess.model.User;
import com.accedo.achievements.services.ajax.AppService;
/**
 * The business logic service of application relevant functionality.
 * @author Bo Liang
 */
@Component
public class AppServiceImpl implements AppService {
	
	private static final Logger log = LoggerFactory.getLogger(AppServiceImpl.class);

	private User user; //injection
	private App app; //injection
	
	private UserDaoImpl userDao; //injection
	private AppDaoImpl appDao; //injection
	private AchievementDaoImpl achiDao; //injection
	
	// Constructor
	AppServiceImpl() {}; 
	
	/**
	 * Get all applications in three state categories : finished, playing and none.
	 * <p>the sequence is grouped by the latest application to the front.
	 * <p>finished state means this user already unlocked all achievements of the application.<br>
	 * playing state means this user has unlocked part of achievements.<br>
	 * none state means this user has never unlocked any achievements related to the application.
	 * @param username	user name
	 * @return			JSON applications<br>
	 * eg. {appsns:[{appsn:'APP012',appname:'Chess Challenge III',state:'none'},
	 * {appsn:'APP011',appname:'Black Jack Pirates III',state:'finished'}]}
	 */
	public JSONObject getJsonAppsnsByUsername(String username) {
		log.debug("### Entering getJsonAppsnsByUsername(username = {})", username);
		
		List<String> appsnList = new ArrayList<String>(); 
		List<App> appList = new ArrayList<App>(); 
		JSONObject jsonObject = new JSONObject(); 
		JSONArray jsonArray = new JSONArray();
		String state = "none"; 
		user = userDao.getUserByUsername(username);
		
		// get the app's sn list which user already have
		appsnList = appDao.getAppsnListByUseid(user.getId()); 
		
		// get all applications
		appList = appDao.getAppList(); 
		
		for(Iterator<App> iter = appList.iterator(); iter.hasNext(); ) {
			app = iter.next();
			// if this user already unlocked the achievement, make state to true
			if (appsnList.contains(app.getApp_sn())) {
				int appNum = achiDao.getAchiQuantityByAppsn(app.getApp_sn());
				int userAppNum = achiDao.getAchiQuantityByUserIdAndAppsn(user.getId(), app.getApp_sn());
				if (userAppNum < appNum) {
					state = "playing";
				} else {
					state = "finished";
				}			 
			} else {
				state = "none"; 	
			}
			jsonObject.element("appsn", app.getApp_sn()); 
			jsonObject.element("appname", app.getApp_name()); 
			jsonObject.element("state", state); 
			jsonArray.add(jsonObject); 
			jsonObject.clear(); 
								
		}
		
		jsonObject.element("appsns", jsonArray); 
		
		try {
			Thread.sleep(1200);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}	
		
		log.debug("### Leaving getJsonAppsnsByUsername() : {}", jsonObject);
		return jsonObject; 
	}
	
	/**
	 * Get all applications in three state categories : finished, playing and none.
	 * <p>the sequence is grouped by finished application, playing application and then none application.
	 * <p>finished state means this user already unlocked all achievements of the application.<br>
	 * playing state means this user has partly unlocked the achievements.<br>
	 * none state means this user has never unlocked any achievements related to the application.
	 * @param username	user name
	 * @return			JSON applications<br>
	 * {appsns:[{appsn:'APP001',appname:'Hungry Harry I',state:'finished'},
	 * {appsn:'APP012',appname:'Chess Challenge III',state:'playing'},
	 * {appsn:'APP011',appname:'Black Jack Pirates III',state:'none'}]}
	 */
	public JSONObject getJsonAppsnsByUsernameForFriendShow(String username) {
		log.debug("### Entering getJsonAppsnsByUsernameForFriendShow(username = {})", username);
		List<String> appsnList = new ArrayList<String>(); 
		List<App> appList = new ArrayList<App>(); 
		JSONObject jsonObject = new JSONObject(); 
		JSONArray jsonArray = new JSONArray();
		JSONArray jsonArrayFinished = new JSONArray();
		JSONArray jsonArrayPlaying = new JSONArray();
		JSONArray jsonArrayNone = new JSONArray();
		user = userDao.getUserByUsername(username);
		
		// get the app's sn list which user already have
		appsnList = appDao.getAppsnListByUseid(user.getId()); 
		
		// get all applications
		appList = appDao.getAppList(); 
		
		for(Iterator<App> iter = appList.iterator(); iter.hasNext(); ) {
			app = iter.next();
			jsonObject.element("appsn", app.getApp_sn()); 
			jsonObject.element("appname", app.getApp_name()); 
			
			// if this user already unlocked the achievement, make state to true
			if (appsnList.contains(app.getApp_sn())) {
				int appNum = achiDao.getAchiQuantityByAppsn(app.getApp_sn());
				int userAppNum = achiDao.getAchiQuantityByUserIdAndAppsn(user.getId(), app.getApp_sn());
				if (userAppNum < appNum) {
					jsonObject.element("state", "playing"); 
					jsonArrayPlaying.add(jsonObject);
					
				} else {
					jsonObject.element("state", "finished"); 
					jsonArrayFinished.add(jsonObject);
				}	
			} else {
				jsonObject.element("state", "none"); 
				jsonArrayNone.add(jsonObject);
			}
			jsonObject.clear();
					
		}
		jsonArray.addAll(jsonArrayFinished);
		jsonArray.addAll(jsonArrayPlaying);
		jsonArray.addAll(jsonArrayNone); 
		jsonObject.element("appsns", jsonArray); 
		
		try {
			Thread.sleep(1200);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}	
		log.debug("### Leaving getJsonAppsnsByUsernameForFriendShow() : {}", jsonObject);
		return jsonObject; 
	}
	
	public User getUser() {
		return user;
	}

	@Resource
	public void setUser(User user) {
		this.user = user;
	}

	public UserDaoImpl getUserDao() {
		return userDao;
	}

	@Resource
	public void setUserDao(UserDaoImpl userDao) {
		this.userDao = userDao;
	}

	public App getApp() {
		return app;
	}

	@Resource
	public void setApp(App app) {
		this.app = app;
	}

	public AppDaoImpl getAppDao() {
		return appDao;
	}

	@Resource
	public void setAppDao(AppDaoImpl appDao) {
		this.appDao = appDao;
	}

	public AchievementDaoImpl getAchiDao() {
		return achiDao;
	}

	@Resource
	public void setAchiDao(AchievementDaoImpl achiDao) {
		this.achiDao = achiDao;
	}
}
